<?php
require_once __DIR__.'/autoload.php';

use common\BaseWorker;
use common\Base;
use common\Log;
use common\Node;

$table = new BaseWorker('frame://0.0.0.0:226');

$table->bucket = [
    'count' => 0,
    'last_change' => 0,
    'bucket'=>[]
];
Log::$config['path'] = 'table/';
$table->table = [
    $table->bucket
];

$table->hashTable = [

];

// $table->hashTable = [
//     'infohash' => [
//         'peers',
//         'peers',
//         'peers',
//     ]
// ];


$table->falseTable = [];
// $table->table = [
//     [
//         'count'=>0,
//         'last_change'=>time()
//     ]
// ];

$table->onMessage = function($conn,$data) use ($table){
    echo "revice message\n";
    $data = unserialize($data);

    switch ($data['action']) {
        case 'addNode':
            // 检查node id是否正确
            if (!isset($data['data']->nid[19]))
            $conn->send(serialize(['status'=>'error']));
            
            // 检查是否为自身node id
            // if ($data['data']->nid == $nid)
            // $conn->send(json_encode(['status'=>'error']));
            
            // 检查node是否已存在
            if (in_array($data['data'], $table->falseTable))
            $conn->send(serialize(['status'=>'error']));
            
            if ($data['data']->port < 1 or $data['data']->port > 65535)
            $conn->send(serialize(['status'=>'error']));
            
            
            $table->addNode(
                $conn,
                $data['data']
            );
            
            break;
        case 'getNodes':

            $target_node = $data['data']['target'];

            $table->getNodes($conn,$target_node);

            break;

        case 'addPeers':

            $infohash = $data['data']['infohash'];

            $peers = $data['data']['peers'];

            $table->addPeers($conn,$infohash,$peers);

            break;

        case 'getPeers':

            $infohash = $data['data']['infohash'];

            $table->getPeers($conn,$infohash);

            break;

        default:
            # code...
            break;
    }

    if(!is_null($conn)){
        $conn->close();
    }

};

$table->getNodes = function($conn,$target_node) use ($table){
    $count = count($table->falseTable);
    if($count>=8){
        $nodes_key = array_rand($table->falseTable,8);
        $nodes = [];
        foreach ($nodes_key as $key_key => $key_value) {
            $nodes[] = $table->falseTable[$key_value];
        }
        $conn->send(serialize($nodes));
    }else{
        Log::record("now count is $count");
        $conn->send(serialize(['error'=>'no useful nodes']));
    }

};

$table->addNode = function($conn,$node) use($table){
    Log::record('add node '.$node->ip.":".$node->port);
    // $key_arr = Base::nodes_ords($nid);
    // $node = new Node($nid,$ip,$port);
    // foreach ($table->table as $table_key => $table_value) {
    //     // if($table_value['count'] == 8){
    //     //     array_push($table->table,$table->bucket);
    //     //     continue;
    //     // }
    //     if($table_value['count'] == 0 ){
    //         array_push($table->table[$table_key]['bucket'],$node);
    //         $table->table[$table_key]['count']++;
    //         break;
    //     }else if($table_value['count'] == 1){
            
    //     }
    // }

    $count = count($table->falseTable);

    if($count > 1200){
        array_shift($table->falseTable);
    }

    if(!in_array($node,$table->falseTable)){
        array_push($table->falseTable,$node);
        $conn->send(serialize(['status'=>'ok']));
    }else{
        $conn->send(serialize(['status'=>'nothing to do']));
    }

    Log::record("now count is ".count($table->falseTable));

};



$table->addPeers = function($conn,$infohash,$peers) use ($table){

    if(!isset($table->hashTable[$infohash])){
        $table->hashTable[$infohash] = [];
    }

    foreach ($peers as $p_key => $p_value) {
        if(!in_array($p_value,$table->hashTable[$infohash])){
            $table->hashTable[$infohash][] = $p_value;
        }
    }

    $conn->send(serialize(['status' => 'ok']));

};

$table->getPeers = function($conn,$infohash) use($table){
    if(isset($table->hashTable[$infohash])){
        if(!empty($table->hashTable[$infohash])){
            $conn->send(serialize($table->hashTable[$infohash]));
            return;
        }
    }else{
        $table->hashTable[$infohash] = [];
    }

    $conn->send(serialize(['error'=>'not find infa hash or peers']));

};



BaseWorker::runAll();